package com.tsd.base.service.impl;

import com.tsd.base.BaseCodeRuleConstants;
import com.tsd.base.dao.BaseCodeRuleItemMapper;
import com.tsd.base.dao.BaseCodeRuleMapper;
import com.tsd.base.dao.BaseRelatedPartyMapper;
import com.tsd.base.entity.*;
import com.tsd.base.service.BaseCodeRuleItemService;
import com.tsd.base.service.BaseCodeRuleService;
import com.tsd.common.service.CommonSnValueService;
import com.tsd.common.vo.BatchDeleteLogicVo;
import com.tsd.core.service.GetDuplicatedObj;
import com.tsd.core.utils.HlpUtils;
import com.tsd.core.utils.ListUtil;
import com.tsd.core.vo.HlpException;
import com.tsd.core.vo.PageBean;
import com.tsd.service.BaseServiceImpl;
import com.tsd.system.entity.SysUser;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;


/**
 * 描述：BaseCodeRule 服务实现层
 *
 * @author zsy
 * @date 2020/12/29 15:22:59
 */
@Service
public class BaseCodeRuleServiceImpl extends BaseServiceImpl implements BaseCodeRuleService {

    @Resource
    private BaseCodeRuleMapper baseCodeRuleMapper;
    @Resource
    private BaseCodeRuleItemMapper baseCodeRuleItemMapper;
    @Resource
    private BaseRelatedPartyMapper baseRelatedPartyMapper;
    @Resource
    private CommonSnValueService commonSnValueService;
    @Resource
    private BaseCodeRuleItemService baseCodeRuleItemService;

    @Override
    public BaseCodeRule getBaseCodeRuleById(Long id) throws Exception {
        return baseCodeRuleMapper.selectByPrimaryKey(id);
    }

    @Override
    public BaseCodeRuleExt queryBySid(String sid) throws Exception {
        return baseCodeRuleMapper.selectBySid(sid);
    }

    @Override
    public void deleteBaseCodeRule(Long id, SysUser opUser) throws Exception {
        BaseCodeRule old = baseCodeRuleMapper.selectByPrimaryKey(id);
        super.checkEmpty(old, "该记录不存在");
        super.autoInjectBaseData(old, opUser, this.TYPE_DELETE);
        baseCodeRuleMapper.updateByPrimaryKeySelective(old);
    }

    @Override
    public void saveBaseCodeRule(BaseCodeRuleExt record, SysUser opUser) throws Exception {
        if (HlpUtils.isEmpty(record.getId())) {
            super.checkEmpty(record.getName(), "编码规则名称不能为空");
            if (HlpUtils.isEmpty(record.getState())) {
                record.setState(1);
            }
            Integer maxSn = baseCodeRuleMapper.selectMaxSn();
            if (maxSn == null) {
                maxSn = 0;
            }
            record.setSn(maxSn + 1);
            super.autoInjectBaseData(record, opUser, this.TYPE_CREATE);
            baseCodeRuleMapper.insertSelective(record);
        } else {
            super.autoInjectBaseData(record, opUser, this.TYPE_UPDATE);
            baseCodeRuleMapper.updateByPrimaryKeySelective(record);
        }
        List<BaseCodeRuleItemExt> itemExtList = record.getData_list();
        if (itemExtList == null || itemExtList.isEmpty()) {
            return;
        }
        List<Long> existIdList = new ArrayList<>();
        List<BaseCodeRuleItemExt> oldList = baseCodeRuleItemMapper.findByCodeRuleSid(record.getSid());
        if (!HlpUtils.isEmptyList(oldList)) {
            for (BaseCodeRuleItemExt itemExt : itemExtList) {
                BaseCodeRuleItemExt oldData = ListUtil.get(oldList, t -> t.getSn().equals(itemExt.getSn()));
                if (oldData != null) {
                    itemExt.setId(oldData.getId());
                    existIdList.add(oldData.getId());
                }
            }
        }
        List<BaseCodeRuleItemExt> delList = ListUtil.filter(oldList, t -> !existIdList.contains(t.getId()));
        if (!HlpUtils.isEmptyList(delList)) {
            List<Long> idList = ListUtil.map(delList, BaseCodeRuleItemExt::getId);
            BatchDeleteLogicVo logicVo = new BatchDeleteLogicVo(opUser);
            logicVo.setIdList(idList);
            baseCodeRuleItemMapper.deleteLogicByIdList(logicVo);
        }
        if (!HlpUtils.isEmptyList(itemExtList)) {
            for (BaseCodeRuleItemExt itemExt : itemExtList) {
                itemExt.setCode_rule_sid(record.getSid());
            }
            this.batchSaveBaseCodeRuleItem(itemExtList, opUser);
        }
    }

    @Override
    public List<BaseCodeRuleExt> findBaseCodeRules(Map<String, Object> params, PageBean page) throws Exception {
        return baseCodeRuleMapper.selectByPage(params, page);
    }

    @Override
    public List<BaseCodeRuleExt> findBaseCodeRules(Map<String, Object> params) throws Exception {
        return baseCodeRuleMapper.selectByParams(params);
    }

    @Override
    public List<BaseCodeRuleExt> queryByEntity(BaseCodeRuleExt params) throws Exception {
        return baseCodeRuleMapper.selectByEntity(params);
    }

    @Override
    public void batchDeleteBaseCodeRule(List<Long> idList, SysUser opUser) throws Exception {
        for (Long id : idList) {
            deleteBaseCodeRule(id, opUser);
        }
    }

    private String genOrderCode(String relatedPartySid, String ruleCode, String rule_name, SysUser opUser, boolean isSave) throws Exception {
        StringBuilder codeBuffer = new StringBuilder();
        List<BaseCodeRuleItemExt> ruleItemList = initGetRuleItem(ruleCode, rule_name);
        Date today = new Date();
        for (BaseCodeRuleItemExt ruleItem : ruleItemList) {
            String code = genTypeCode(ruleItem, ruleCode, relatedPartySid, today, opUser, isSave, false);
            if (!HlpUtils.isEmpty(code)) {
                codeBuffer.append(code);
            }
        }
        return codeBuffer.toString();
    }

    /**
     * 初始化编码规则记录
     *
     * @param ruleCode
     * @param rule_name
     * @throws Exception
     */
    private void initRule(String ruleCode, String rule_name) throws Exception {
        BaseCodeRuleExt t = new BaseCodeRuleExt();
        t.setCode(ruleCode);
        t.setName(rule_name);
        this.saveBaseCodeRule(t, null);
        this.initRuleItems(t.getSid());
    }

    /**
     * 初始化规则项：基于天，序号为4位，9999条记录
     *
     * @param rule_sid
     * @throws Exception
     */
    private void initRuleItems(String rule_sid) throws Exception {
        List<BaseCodeRuleItemExt> items = new ArrayList<>();
        BaseCodeRuleItemExt i1 = new BaseCodeRuleItemExt();
        i1.setCode_rule_sid(rule_sid);
        i1.setType(BaseCodeRuleConstants.TYPE_DATE);
        i1.setValue1(BaseCodeRuleConstants.TYPE_DATE_VALUE1_YYMM);
        items.add(i1);
        BaseCodeRuleItemExt i2 = new BaseCodeRuleItemExt();
        i2.setCode_rule_sid(rule_sid);
        i2.setType(BaseCodeRuleConstants.TYPE_FIX);
        i2.setValue1("-");
        items.add(i2);
        BaseCodeRuleItemExt i3 = new BaseCodeRuleItemExt();
        i3.setCode_rule_sid(rule_sid);
        i3.setType(BaseCodeRuleConstants.TYPE_SN);
        i3.setValue1(BaseCodeRuleConstants.TYPE_SN_VALUE1_YYMM);
        i3.setValue2(4);
        i3.setValue3(0);
        i3.setValue4(0);
        items.add(i3);
        batchSaveBaseCodeRuleItem(items, null);
    }

    @Override
    public String genOrderCode4Example(String ruleCode, SysUser opUser) throws Exception {
        StringBuilder codeBuffer = new StringBuilder();
        BaseCodeRuleExt codeRule = baseCodeRuleMapper.getByCode(ruleCode);
        if (codeRule != null) {
            List<BaseCodeRuleItemExt> ruleItemList = baseCodeRuleItemMapper.findByCodeRuleSid(codeRule.getSid());
            if (!HlpUtils.isEmptyList(ruleItemList)) {
                Date today = new Date();
                for (BaseCodeRuleItemExt ruleItem : ruleItemList) {
                    String code = genTypeCode(ruleItem, ruleCode, null, today, opUser, false, true);
                    if (!HlpUtils.isEmpty(code)) {
                        codeBuffer.append(code);
                    }
                }
                return codeBuffer.toString();
            } else {
                throw new HlpException("未设置该编码规则明细！");
            }
        } else {
            throw new HlpException("未设置该编码规则！");
        }
    }

//    @Override
//    public String genCode(String client_sid, String supplier_sid, String rule_code, SysUser opUser, String code, Object obj, GetDuplicatedObj getDuplicatedObj) throws Exception {
//        return this.genCode(client_sid, supplier_sid, rule_code, null, opUser, code, obj, getDuplicatedObj);
//    }

    /**
     * 检查编码是否与生成的编码一致
     * 如果一致，则编码规则加1
     *
     * @param related_party_sid
     * @param rule_code
     * @param opUser
     * @param code
     * @return
     * @throws Exception
     */
    private String checkGenCode(String related_party_sid, String rule_code, String rule_name, SysUser opUser, String code) throws Exception {
        if (HlpUtils.isEmpty(code)) {
            return this.genOrderCode(related_party_sid, rule_code, rule_name, opUser, true);
        }
        String genCode = this.genOrderCode(related_party_sid, rule_code, rule_name, opUser, false);
        //如果多人操作，大家都在打开的界面中获取到相同的编码A，分别保存的时候，第一个是正确的，但之后的由于genCode.equals(code)为true，直接以打开界面时的编码保存，从而形成了编码相同的情况
        //为了避免此情况，当保存的时候，如果ID为空，或者是复制的记录，或者切换的编码相关的记录，需要将code设置为null
        if (genCode.equals(code)) {
            return this.genOrderCode(related_party_sid, rule_code, rule_name, opUser, true);
        }
        return code;
    }

    @Override
    public synchronized String genCode(String related_party_sid, String rule_code, String rule_name, SysUser opUser, String code, Object obj, GetDuplicatedObj getDuplicatedObj) throws Exception {
        //自动编码，判断是否重复，如果重复，则进行重新编码
        int count = 0;
        String genCode;
        while (true) {
            genCode = checkGenCode(related_party_sid, rule_code, rule_name, opUser, code);
            //如果有检查重复方法，则调用该方法
            if (getDuplicatedObj != null) {
                boolean isDup = getDuplicatedObj.isDuplicated(obj, genCode);
                if (!isDup) {
                    break;
                } else {
                    code = null;
                }
            } else {
                //如果没有检查重复方法，直接返回获取的code
                break;
            }
            count++;
            if (count > 100) {
                throw new HlpException("已检查100个编码，仍然重复，请与开发服务商联系");
            }
        }
        return genCode;
    }

    /**
     * 根据规则项生成编号的一部分
     *
     * @param ruleItem
     * @param relatedPartySid
     * @return
     * @throws Exception
     */
    private String genTypeCode(BaseCodeRuleItemExt ruleItem, String ruleCode, String relatedPartySid, Date today, SysUser opUser, boolean isSave, boolean isExample) throws Exception {
        StringBuilder codeBuffer = new StringBuilder();
        if (BaseCodeRuleConstants.TYPE_FIX == ruleItem.getType()) {
            // 固定值
            codeBuffer.append(ruleItem.getValue1());
        } else if (BaseCodeRuleConstants.TYPE_DATE == ruleItem.getType()) {
            // 日期格式
            String code = HlpUtils.date2String(today, ruleItem.getValue1());
            codeBuffer.append(code);
        } else if (BaseCodeRuleConstants.TYPE_AUTO_TEXT == ruleItem.getType()) {
            if (isExample) {
                // 动态文本
                if (BaseCodeRuleConstants.TYPE_AUTO_TEXT_VALUE_1_RELATED_PARTY.equals(ruleItem.getValue1())) {
                    // 客户简称
                    codeBuffer.append("往来单位简称");
                }
            } else {
                // 动态文本
                if (BaseCodeRuleConstants.TYPE_AUTO_TEXT_VALUE_1_RELATED_PARTY.equals(ruleItem.getValue1())) {
                    // 往来单位简称
                    if (!HlpUtils.isEmpty(relatedPartySid)) {
                        BaseRelatedPartyExt partyExt = baseRelatedPartyMapper.selectBySid(relatedPartySid);
                        if (partyExt != null && !HlpUtils.isEmpty(partyExt.getShort_name())) {
                            codeBuffer.append(partyExt.getShort_name());
                        }
                    }
                }
            }
        } else if (BaseCodeRuleConstants.TYPE_SN == ruleItem.getType()) {
            //序号类型，构建序号计算的基础（tempCode)，然后据此到commonSnValue去查询序号
            StringBuilder tempCode = new StringBuilder();
            tempCode.append(ruleCode);
            // 顺序号
            if (!HlpUtils.isEmpty(ruleItem.getValue3()) && BaseCodeRuleConstants.TYPE_SN_VALUE3_RELATED_PARTY == ruleItem.getValue3()) {
                // 往来单位
                if (!HlpUtils.isEmpty(relatedPartySid)) {
                    tempCode.append("-");
                    tempCode.append(relatedPartySid);
                }
            }
            tempCode.append("-");
            //tempCode加上以日期所所对应的字符：年、年月、年月日
            tempCode.append(HlpUtils.date2String(today, ruleItem.getValue1()));
            // 位数
            Integer num = ruleItem.getValue2();
            int sn = commonSnValueService.genNextValue(tempCode.toString(), num, opUser, isSave);
            //位数不够则前面补零
            codeBuffer.append(HlpUtils.getLenStrWithPreChar(sn + "", num, "0"));
        } else {
            throw new HlpException("无此类型编码明细！");
        }
        return codeBuffer.toString();
    }

    @Override
    public void batchSaveBaseCodeRuleItem(List<BaseCodeRuleItemExt> list, SysUser opUser) throws Exception {
        for (BaseCodeRuleItemExt itemExt : list) {
            baseCodeRuleItemService.saveBaseCodeRuleItem(itemExt, opUser);
        }
        List<String> codeRuleList = ListUtil.map(list, BaseCodeRuleItem::getCode_rule_sid);
        if (!HlpUtils.isEmptyList(codeRuleList)) {
            BaseCodeRuleExt params = new BaseCodeRuleExt();
            params.setDr(0);
            params.setSid_list(codeRuleList);
            List<BaseCodeRuleExt> ruleExtList = queryByEntity(params);
            for (BaseCodeRuleExt ruleExt : ruleExtList) {
                String code = genOrderCode4Example(ruleExt.getCode(), opUser);
                ruleExt.setSample_code(code);
                baseCodeRuleMapper.updateByPrimaryKeySelective(ruleExt);
            }
        }
    }

    private List<BaseCodeRuleItemExt> initGetRuleItem(String ruleCode, String rule_name) throws Exception {
        if (HlpUtils.isEmpty(rule_name)) {
            rule_name = BaseCodeRuleConstants.getRuleName(ruleCode);
        }
        BaseCodeRuleExt codeRule = baseCodeRuleMapper.getByCode(ruleCode);
        if (codeRule == null) {
            initRule(ruleCode, rule_name);
            codeRule = baseCodeRuleMapper.getByCode(ruleCode);
        }
        List<BaseCodeRuleItemExt> ruleItemList = baseCodeRuleItemMapper.findByCodeRuleSid(codeRule.getSid());
        if (HlpUtils.isEmptyList(ruleItemList)) {
            initRuleItems(codeRule.getSid());
            ruleItemList = baseCodeRuleItemMapper.findByCodeRuleSid(codeRule.getSid());
        }
        return ruleItemList;
    }

    @Override
    public String getNextCode(String ruleCode, String rule_name, Map<String, Object> factorMap) throws Exception {
        StringBuilder codeBuffer = new StringBuilder();
        List<BaseCodeRuleItemExt> ruleItemList = this.initGetRuleItem(ruleCode, rule_name);
        String partySid = HlpUtils.getString(factorMap, BaseCodeRuleConstants.RULE_ITEM_PARAM_NAME_RELATED_PARTY_SID);
        Date today = new Date();
        for (BaseCodeRuleItemExt ruleItem : ruleItemList) {
            String code = genTypeCode(ruleItem, ruleCode, partySid, today, null, false, false);
            if (!HlpUtils.isEmpty(code)) {
                codeBuffer.append(code);
            }
        }
        return codeBuffer.toString();
    }
}
